package edu.hdu.hangzhe.core;

import edu.hdu.hangzhe.bytecode.MyClassVisitor;
import edu.hdu.hangzhe.bytecode.domain.*;
import edu.hdu.hangzhe.utils.FileUtils;
import org.objectweb.asm.*;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


public class BytecodeParser {
    /**
     * 字节码解析ABIL
     * 返回ByteCode
     */
    public static ByteCode parse(String path, String className) {
        className = className.replaceAll("\\.", "/");
        className = className + ".class";
        String filepath = FileUtils.getFilePath(path, className);
        byte[] bytes = FileUtils.readBytes(filepath);
        ClassReader cr = new ClassReader(bytes);
        // 串连ClassVisitor
        int api = Opcodes.ASM8;
        MyClassVisitor cv = new MyClassVisitor(api);
        int parsingOptions = ClassReader.SKIP_FRAMES;
        cr.accept(cv, parsingOptions);
        return cv.getByteCode();
    }

    public static Map<String, ByteCode> parseProject(String path) {
        File dir = new File(path);
        if (!dir.isDirectory()) {
            System.err.println("not dir! " + path);
            return null;
        }
        String packageName = "";
        Map<String, ByteCode> record = new HashMap<>();
        traverse(dir, record, packageName, path);
        return record;
    }

    private static void traverse(File dir, Map<String, ByteCode> record, String packageName, String root) {
        String name = dir.getName();
        if (name.equals(".DS_Store")) {
            return;
        }
        if (dir.isFile()) {
            if (".class".equals(name.substring(name.length() - 6))) {

                String clas = packageName.substring(0, packageName.length() - 7);
                System.out.println(clas);
                ByteCode byteCode = BytecodeParser.parse(root, clas);
                record.put(clas, byteCode);
            }
            return;
        }
        for (File file : Objects.requireNonNull(dir.listFiles())) {
            traverse(file, record, packageName + file.getName() + ".", root);
        }
    }
}